/// $Id$
// Author : Anushi Shah, Kyoungho An

#include <string>
using namespace std;


////////////////////////
#include "ace/Get_Opt.h"  // for parsing command line
#include "ace/Log_Msg.h"  // for logging messages
#include "ace/Sched_Params.h"  // for scheduling params
#include "ace/Task.h"  // for the main thread of control

#include "tao/ORB_Core.h" // the ORB itself
#include "tao/RTCORBA/RTCORBA.h"  // all the RTCORBA capabilities
#include "tao/RTPortableServer/RTPortableServer.h" // for RT POA

#include "TurnaroundNEANode_i.h"  // our implementation header
#include "Utils.h"
#include "NEANodeClient.h"
#include "NEANodeInternalClient.h"
#include "ace/Sched_Params.h"

#include "tao/ORBInitializer_Registry.h"
#include "tao/RTCORBA/RTCORBA.h"
#include "tao/RTCORBA/Priority_Mapping_Manager.h"
#include "ace/Get_Opt.h"
#include "orbsvcs/CosNamingC.h"
#include "ftrtcs/TurnaroundActuatorC.h"
#include "ftrtcs/TurnaroundNEANodeC.h"

#include <iostream>

NEANodeClient *nea;
NEANodeInternalClient *nea_int;
Block_Turnaround_TurnaroundNEANode_i *servant=NULL;

CORBA::ORB_var nea_orb;
CORBA::ORB_var nea_intorb;

/**************************************************************************/
/// the main function. 
/*const ACE_TCHAR *ior = ACE_TEXT("file://../diag1");
int
parse_args (int argc, ACE_TCHAR *argv[])
{
  ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("k:"));
  int c;

  while ((c = get_opts ()) != -1)
    switch (c)
      {
      case 'k':
        ior = get_opts.opt_arg ();
        break;
      case '?':
      default:
        ACE_ERROR_RETURN ((LM_ERROR,
                           "usage:  %s "
                           "-k <ior> "
                           "\n",
                           argv [0]),
                          -1);
      }

  return 0;
}*/
/////////////////////////////////////////

/**************************************************************************/
// files where the IOR will be output
const ACE_TCHAR *dir = ACE_TEXT ("..");
const ACE_TCHAR *file0 = ACE_TEXT("diag0");
const ACE_TCHAR *file1 = ACE_TEXT("diag1");
const ACE_TCHAR *file2 = ACE_TEXT("diag2");
CORBA::Short poa_priority = 5;  // poa level priority
CORBA::Short obj_priority = 10;  // obj level priority
string ior_file0;
string ior_file1;
string ior_file2;



const ACE_TCHAR *ds_file = ACE_TEXT("dsensor");
const ACE_TCHAR *us_file = ACE_TEXT("usensor");


string ds_ior_file;
string us_ior_file;


/**************************************************************************/
/// parse arguments
int parse_args (int argc, ACE_TCHAR *argv[])
{
  // a utility provided in ACE
  ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("k:o:p:"));
  int c, result;

  while ((c = get_opts ()) != -1)
    switch (c)
      {
      case 'k': // directory where ior is generated. Default is one level up
        dir = get_opts.opt_arg ();
        break;

      case 'o':  // indicates priority level for obj to be executed at
        result = ::sscanf (ACE_TEXT_ALWAYS_CHAR (get_opts.opt_arg ()),
                           "%hd",
                           &obj_priority);
        if (result == 0 || result == EOF)
          ACE_ERROR_RETURN ((LM_ERROR,
                             "Unable to process <-o> option"),
                            -1);
        break;

      case 'p':  // indicates priority level for POA
        result = ::sscanf (ACE_TEXT_ALWAYS_CHAR (get_opts.opt_arg ()),
                           "%hd",
                           &poa_priority);
        if (result == 0 || result == EOF)
          ACE_ERROR_RETURN ((LM_ERROR,
                             "Unable to process <-p> option"),
                            -1);
        break;

      case '?':
      default:
        ACE_ERROR_RETURN ((LM_ERROR,
                           "usage:  %s "
                           "-k <directory of IOR file> "
                           "-o <obj-level priority> "
                           "-p <POA-level priority> "
                           "\n",
                           argv [0]),
                          -1);
      }

  // create the full file names for ior files
  ior_file0 = 
    string (dir) + 
    ACE_DIRECTORY_SEPARATOR_CHAR +
    string (file0);

  ior_file1 = 
    string (dir) + 
    ACE_DIRECTORY_SEPARATOR_CHAR +
    string (file1);

  ior_file2 = 
    string (dir) + 
    ACE_DIRECTORY_SEPARATOR_CHAR +
    string (file2);

    ior_file2 = 
    string (dir) + 
    ACE_DIRECTORY_SEPARATOR_CHAR +
    string (file2);

   ds_ior_file = 
    string (dir) + 
    ACE_DIRECTORY_SEPARATOR_CHAR +
    string (ds_file);

   us_ior_file = 
    string (dir) + 
    ACE_DIRECTORY_SEPARATOR_CHAR +
    string (us_file);


  // Indicates sucessful parsing of the command line
  return 0;
}

////////////////////////////////////////////////////////
//*********** Start of NEAInternal Client Task ***********///
class NEAInternalClientTask : public ACE_Task_Base
{
public:

  NEAInternalClientTask (ACE_Thread_Manager &thread_manager,
        CORBA::ORB_ptr orb);

  int svc (void);

  CORBA::ORB_var orb_;
  Block::Turnaround::TurnaroundActuator_var server;
};

NEAInternalClientTask::NEAInternalClientTask (ACE_Thread_Manager &thread_manager,
            CORBA::ORB_ptr orb)
  : ACE_Task_Base (&thread_manager),
    orb_ (CORBA::ORB::_duplicate (orb))
{
}

int
NEAInternalClientTask::svc (void)
{
  try
    {
      if (nea_int->init () == -1) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("main: nea init failed\n")));
        return 0;
      }
      
      // now essentially hand over control to the ORB
      nea_intorb->run ();
    }
  catch (const CORBA::DATA_CONVERSION& ex)
    {
      ex._tao_print_exception (
        "Most likely, this is due to the in-ability ""to set the thread priority.");
      return -1;
    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Caught exception:");
      return -1;
    }

  return 0;
}



//////*************** End of NEAInternal Client Task **************//

//************* Start of NEAInternal Server Task *************//

class NEAInt_ServerTask : public ACE_Task_Base
{
public:

  // constructor
  NEAInt_ServerTask (ACE_Thread_Manager &thread_manager,
        CORBA::ORB_ptr orb);

  // this is where all the logic for the thread goes in
  int svc (void);

private:
  CORBA::ORB_var neaint_orb_;

};


NEAInt_ServerTask::NEAInt_ServerTask (ACE_Thread_Manager &thread_manager,
            CORBA::ORB_ptr orb)
  : ACE_Task_Base (&thread_manager),
    neaint_orb_ (CORBA::ORB::_duplicate (orb))
{
}


int
NEAInt_ServerTask::svc (void)
{
  try
    {
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: Inside the SVC method\n")));

      
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: acquire the RTORB\n")));
      CORBA::Object_var neaint_object =
        this->neaint_orb_->resolve_initial_references ("RTORB");

      
      if (CORBA::is_nil (neaint_object.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot acquire RTORB\n")));
        return 1;
      }

      
      RTCORBA::RTORB_var rt_orb_neaint = RTCORBA::RTORB::_narrow (neaint_object.in ());

     
      if (CORBA::is_nil (rt_orb_neaint.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot narrow to RTORB\n")));
        return 1;
      }

      
      try 
        {
          ACE_DEBUG ((LM_DEBUG,
                      ACE_TEXT ("NEANodeInternal_Server: demonstrating an exception\n")));
         
          CORBA::String_var rtior = 
            this->neaint_orb_->object_to_string (rt_orb_neaint.in ());
        } 
      catch (const CORBA::Exception& e) 
        {
          e._tao_print_exception ("Exception caught");
          ACE_DEBUG ((LM_DEBUG,
                      ACE_TEXT ("NEANodeInternal_Server: resuming from this exception\n")));
        }

    
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: acquire the RootPOA\n")));
      neaint_object =
        this->neaint_orb_->resolve_initial_references ("RootPOA");

      // defensive programming - check for errors
      if (CORBA::is_nil (neaint_object.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot acquire RootPOA\n")));
        return 1;
      }

      
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: narrow it to RT-enabled RootPOA\n")));
      RTPortableServer::POA_var root_poa_neaint =
        RTPortableServer::POA::_narrow (neaint_object.in ());

      // defensive programming - check for errors
      if (CORBA::is_nil (root_poa_neaint.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot narrow to RT-enabled POA\n")));
        return 1;
      }

    
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: acquire a POA manager\n")));
      PortableServer::POAManager_var poa_manager_neaint =
        root_poa_neaint->the_POAManager ();

      std::cout << "** 1 ** " << std::endl;

      RTPortableServer::POA_var child_rt_poa_neaint =  
        create_poa_with_server_declared_model (rt_orb_neaint.in (),
                                               root_poa_neaint.in (),
                                               poa_manager_neaint.in (),
                                               poa_priority);

     std::cout << "** 2 ** " << std::endl;
      // defensive programming - check for errors
     if (CORBA::is_nil (child_rt_poa_neaint.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot acquire child rt poa\n")));
        return 1;
      }

     ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANode: instantiate our implementation\n")));
      Block_Turnaround_TurnaroundNEANode_i *nea_intservant = 
        new Block_Turnaround_TurnaroundNEANode_i (this->neaint_orb_.in (),
                               rt_orb_neaint.in (),nea_int);

    // defensive programming - check for errors
      if (!nea_intservant) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot allocate an impl\n")));
        return 1;
      }

       CORBA::Object_var msg_obj;

      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: create first obj reference with root POA\n")));
      if (create_and_publish_diag_object (this->neaint_orb_.in (),
                                          root_poa_neaint.in (),
                                          nea_intservant,
                                          -1,
                                          ior_file0.c_str (),msg_obj) == -1) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot create and register obj with rootPOA\n")));
        return 1;
      }

      
      // second one goes with child poa but with the priority of the child poa
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: create second obj reference at child POA priority\n")));
      if (create_and_publish_diag_object (this->neaint_orb_.in (),
                                          child_rt_poa_neaint.in (),
                                          nea_intservant,
                                          -1,
                                          ds_ior_file.c_str (),msg_obj) == -1) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot create and register obj with child rt poa\n")));
        return 1;
      }

      // third one goes with child poa with object level priority
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: create third obj reference with obj level override\n")));
      if (create_and_publish_diag_object (this->neaint_orb_.in (),
                                          child_rt_poa_neaint.in (),
                                          nea_intservant,
                                          obj_priority,
                                          us_ior_file.c_str (),msg_obj) == -1) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal_Server: Cannot create and register obj with child poa at obj level priority\n")));
        return 1;
      }

      
     
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: activate the POA manager\n")));
      poa_manager_neaint->activate ();

      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal_Server: Now let the ORB take over\n")));
      this->neaint_orb_->run ();

    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Exception caught");
      return -1;
    }

  // if and when the ORB returns, we get here
  return 0;

}
//**************End of NEAInternal Server Task **************//

//************** Start of NEANode as External server *******//
class Server_Task : public ACE_Task_Base
{
public:

  // constructor
  Server_Task (ACE_Thread_Manager &thread_manager,
        CORBA::ORB_ptr orb);

  // this is where all the logic for the thread goes in
 int svc (void);

//private:
  CORBA::ORB_var orb_;

};

// constructor
Server_Task::Server_Task (ACE_Thread_Manager &thread_manager,
            CORBA::ORB_ptr orb)
  : ACE_Task_Base (&thread_manager),
    orb_ (CORBA::ORB::_duplicate (orb))
{
}

// main logic
int
Server_Task::svc (void)
{
  try
    {

      // we came here because of the call to "activate" in main program.  4
      // steps were done in main (). The remainder are done here.
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : Inside the SVC meithod\n")));

      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : acquire the RTORB\n")));
      CORBA::Object_var object =
        this->orb_->resolve_initial_references ("RTORB");

      // defensive programming - check for errors
      if (CORBA::is_nil (object.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot acquire RTORB\n")));
        return 1;
      }

      // we must now narrow it to the right type
      RTCORBA::RTORB_var rt_orb = RTCORBA::RTORB::_narrow (object.in ());

      // defensive programming - check for errors
      if (CORBA::is_nil (rt_orb.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot narrow to RTORB\n")));
        return 1;
      }

      // this block of code is for demo purpose only to show that we cannot
      // stringify the RTORB's reference.
      try 
        {
          ACE_DEBUG ((LM_DEBUG,
                      ACE_TEXT ("NEAExternal_Server: demonstrating an exception\n")));
          // let us try to stringify ref of RTORB, which should throw an
          // exception called MARSHAL because RTORB is a local interface and
          // cannot be stringified or sent to remote location as a parameter.
          CORBA::String_var rtior = 
            this->orb_->object_to_string (rt_orb.in ());
        } 
      catch (const CORBA::Exception& e) 
        {
          e._tao_print_exception ("Exception caught");
          ACE_DEBUG ((LM_DEBUG,
                      ACE_TEXT ("NEAExternal_Server: resuming from this exception\n")));
        }

      // RootPOA that we acquire next will automatically be "RT-enabled".
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server: acquire the RootPOA\n")));
      object =
        this->orb_->resolve_initial_references ("RootPOA");

      // defensive programming - check for errors
      if (CORBA::is_nil (object.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server: Cannot acquire RootPOA\n")));
        return 1;
      }

      // remember to narrow it to the right type. If the following succeeds,
      // then it implies that the basic ORB gave us a RT-enabled RootPOA
      // (because it was RT-enabled).
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : narrow it to RT-enabled RootPOA\n")));
      RTPortableServer::POA_var root_poa =
        RTPortableServer::POA::_narrow (object.in ());

      // defensive programming - check for errors
      if (CORBA::is_nil (root_poa.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot narrow to RT-enabled POA\n")));
        return 1;
      }

      // Now acquire the POA manager. This is needed for many things as we will
      // see shortly. For one, it maintains the state of each POA.
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : acquire a POA manager\n")));
      PortableServer::POAManager_var poa_manager =
        root_poa->the_POAManager ();

      
       // function we wrote to avoid code cluttering.
      RTPortableServer::POA_var child_rt_poa =  
        create_poa_with_client_declared_model (rt_orb.in (),
                                               root_poa.in (),
                                               poa_manager.in (),
                                               poa_priority);

      // defensive programming - check for errors
      if (CORBA::is_nil (child_rt_poa.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot acquire child rt poa\n")));
        return 1;
      }

      // now instantiate our implementation class
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : instantiate our implementation\n")));

                  
      servant = 
        new Block_Turnaround_TurnaroundNEANode_i (this->orb_.in (),
                               rt_orb.in ());

      CORBA::Object_var msg_obj;
                               


      if (!servant) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot allocate an impl\n")));
        return 1;
      }


      // first one goes with root poa
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : create first obj reference with root POA\n")));
      if (create_and_publish_diag_object (this->orb_.in (),
                                          root_poa.in (),
                                          servant,
                                          -1,
                                          ior_file0.c_str (), msg_obj) == -1) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot create and register obj with rootPOA\n")));
        return 1;
      }

      
      // second one goes with child poa but with the priority of the child poa
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server :  create second obj reference at child POA priority\n")));
      if (create_and_publish_diag_object (this->orb_.in (),
                                          child_rt_poa.in (),
                                          servant,
                                          -1,
                                          ior_file1.c_str (), msg_obj) == -1) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot create and register obj with child rt poa\n")));
        return 1;
      }

      // third one goes with child poa with object level priority
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : create third obj reference with obj level override\n")));
      if (create_and_publish_diag_object (this->orb_.in (),
                                          child_rt_poa.in (),
                                          servant,
                                          obj_priority,
                                          ior_file2.c_str (), msg_obj) == -1) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot create and register obj with child poa at obj level priority\n")));
        return 1;
      }

      
      
      // activate the POA so that it can start accepting requests.
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : activate the POA manager\n")));
      poa_manager->activate ();
     // Naming Service code //////////////////////////////////
     // Find the Naming Service
    CORBA::Object_var obj =
      orb_->resolve_initial_references("NameService");
     
     CosNaming::NamingContext_var root1 =
      CosNaming::NamingContext::_narrow( obj.in() );
  
     if (CORBA::is_nil(root1.in())) {
      
       ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : Naming Service nil \n")));
      return 1;
     }

      // Bind the example Naming Context, if necessary
    CosNaming::Name name;
    name.length( 1 );
    name[0].id = CORBA::string_dup( "example" );
    try {
      CORBA::Object_var dummy = root1->resolve( name );
    }
    catch(const CosNaming::NamingContext::NotFound&) {
      CosNaming::NamingContext_var dummy = root1->bind_new_context( name );
    }

     // Bind the Messenger object
     name.length( 2 );
     name[1].id = CORBA::string_dup( "Messenger" );


    
    root1->rebind(name, msg_obj.in());
    
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : Bound to Naming Service\n")));



      // defensive programming - check for errors




      this->orb_->run ();
      this->orb_->destroy ();

    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Exception caught");
      return -1;
    }

  // if and when the ORB returns, we get here
  return 0;

}



//***   NEANode External Client **********/////////////////
class Task : public ACE_Task_Base
{
public:

  Task (ACE_Thread_Manager &thread_manager,
        CORBA::ORB_ptr orb);

  int svc (void);

  CORBA::ORB_var orb_;
  Block::Turnaround::TurnaroundNEANode_var server;

};

Task::Task (ACE_Thread_Manager &thread_manager,
            CORBA::ORB_ptr orb)
  : ACE_Task_Base (&thread_manager),
    orb_ (CORBA::ORB::_duplicate (orb))
{
   std::cout << "In Task ctr()......" << std::endl;
}

int
Task::svc (void)
{
  try
    {
     
      
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("***********In Task(svc()...........*******)\n")));
      while (nea->init () == -1) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("main: nea init failed\n")));
        //return 0;
      }
      
      // now essentially hand over control to the ORB
      nea_orb->run ();
    }
  catch (const CORBA::DATA_CONVERSION& ex)
    {
      ex._tao_print_exception (
        "Most likely, this is due to the in-ability ""to set the thread priority.");
      return -1;
    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Caught exception:");
      return -1;
    }

  return 0;
}


int
ACE_TMAIN(int argc, ACE_TCHAR *argv[])
{
   int result, client_result;
   ACE_Thread_Manager thread_manager;
   ACE_Thread_Manager server_thread_manager;
   ACE_Thread_Manager intclient_thread_manager;
   ACE_Thread_Manager intserver_thread_manager;
   
   int int_client_result;
   int int_server_result;
   

 // ************ NEANode as External Server code for NEANode*************************
 try
    {
      
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : acquire the ORB\n")));
      CORBA::ORB_var orb =
        CORBA::ORB_init (argc, argv);
      
      // defensive programming - check for errors
      if (CORBA::is_nil (orb.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEAExternal_Server : Cannot acquire ORB\n")));
        return 1;
      }

     if (!check_supported_priorities (orb.in ()))
        return 2;

      // parse the arguments
    ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : parse arguments\n")));
      int result = parse_args (argc, argv);
      if (result != 0)
        return result;

    //ACE_Thread_Manager thread_manager;

      // Create task.
      Server_Task task (server_thread_manager,
                 orb.in ());

      // Task activation flags. We create a lightweight process and wait to
      // have the thread send its status back.
      long flags =
        THR_NEW_LWP |
        THR_JOINABLE |
        orb->orb_core ()->orb_params ()->thread_creation_flags ();

     // Activate task (spawns a thread).  All the remaining steps are done in
      // the "svc" method of this task.
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEAExternal_Server : spawn a task\n")));
      result =
        task.activate (flags);
      if (result == -1)
        {
          // check what could have gone wrong. Maybe we did not have
          // permissions to run the real-time stuff.
          if (errno == EPERM)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 "Cannot create thread with scheduling policy %s\n"
                                 "because the user does not have the appropriate privileges, terminating program....\n"
                                 "Check svc.conf options and/or run as root\n",
                                 sched_policy_name (orb->orb_core ()->orb_params ()->ace_sched_policy ())),
                                2);
            }
          else
            // Unexpected error.
            ACE_ASSERT (0);
        }

      //result =
       // thread_manager.wait ();
      ACE_ASSERT (result != -1);
    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Exception caught");
      return -1;
    }


 // ************ NEANode as External Client code for NEANode*************************

    try
    {
    // Initialize and obtain reference to the Test object.
        nea_orb = CORBA::ORB_init (argc, argv);
       
       while(servant==NULL){
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("Servant was not instatiated\n")));
       }

      // instantiate a NEA node object
       nea = new NEANodeClient(nea_orb.in (), servant->status());
     
      // parse the remaining arguments
       int nea_result =
        nea->parse_args (argc, argv);

      // check for errors
      if (nea_result != 0) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("main: parsing failed\n")));
        return 0;
      }

      // Make sure we can support multiple priorities that are required
      // for this test.
      if (!check_supported_priorities (nea_orb.in ()))
        return 2;

      // Thread Manager for managing task.
      // ACE_Thread_Manager thread_manager;

      // Create task.
      Task task (thread_manager,
                 nea_orb.in ());

      // Task activation flags.
      long flags =
        THR_NEW_LWP |
        THR_JOINABLE |
        nea_orb->orb_core ()->orb_params ()->thread_creation_flags ();

      // Activate task.
      int client_result =
        task.activate (flags);
      if (client_result == -1)
        {
          if (errno == EPERM)
            {
             ACE_ERROR_RETURN ((LM_ERROR,
                                 "Cannot create thread with scheduling policy %s\n"
                                 "because the user does not have the appropriate privileges, terminating program....\n"
                                 "Check svc.conf options and/or run as root\n",
                                 sched_policy_name (nea_orb->orb_core ()->orb_params ()->ace_sched_policy ())),
                                2);
            }
          else
            // Unexpected error.
            ACE_ASSERT (0);
        }

      // Wait for task to exit.
     // result =
      //  thread_manager.wait ();
      ACE_ASSERT (client_result != -1);
    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Caught exception:");
      return -1;
    }



//////////////////////////////////////////////////////////////////////////////
//********************* Start of NEANode_InternalClient Thread for Actuator****************************************
 
    // Thread Manager for managing task.
   

    try
    {
   // Initialize and obtain reference to the Test object.
        nea_intorb = CORBA::ORB_init (argc, argv);

      // instantiate a NEA node object
       nea_int = new NEANodeInternalClient(nea_intorb.in ());
     
      // parse the remaining arguments
      int neaint_result =
        nea_int->parse_args (argc, argv);

      // check for errors
      if (neaint_result != 0) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("main: parsing failed\n")));
        return 0;
      }

      // Make sure we can support multiple priorities that are required
      // for this test.
      if (!check_supported_priorities (nea_intorb.in ()))
        return 2;

      // Create task.
      NEAInternalClientTask intclient_task (intclient_thread_manager,
                 nea_intorb.in ());

      // Task activation flags.
      long client_flags =
        THR_NEW_LWP |
        THR_JOINABLE |
        nea_intorb->orb_core ()->orb_params ()->thread_creation_flags ();

      // Activate task.
      int_client_result =
        intclient_task.activate (client_flags);
      if (int_client_result == -1)
        {
          if (errno == EPERM)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 "Cannot create thread with scheduling policy %s\n"
                                 "because the user does not have the appropriate privileges, terminating program....\n"
                                 "Check svc.conf options and/or run as root\n",
                                 sched_policy_name (nea_orb->orb_core ()->orb_params ()->ace_sched_policy ())),
                                2);
            }
          else
            // Unexpected error.
            ACE_ASSERT (0);
        }


      ACE_ASSERT (int_client_result != -1);

    }
    catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Caught exception:");
      return -1;
    }


//************************End of NEANode_InternalClient Thread for Actuator **************************************


//*************Start of NEANode_InternalServer Thread for Sensors *******************

    try
    {

        ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal Server: acquire the ORB\n")));
      CORBA::ORB_var neaint_server_orb =
        CORBA::ORB_init (argc, argv);
      
      // defensive programming - check for errors
      if (CORBA::is_nil (neaint_server_orb.in ())) {
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("NEANodeInternal Server: Cannot acquire ORB\n")));
        return 1;
      }

      
      // Make sure we can support multiple priorities that are required
      // for this test.
      //if (!check_supported_priorities (orb.in ()))
       // return 2;

      
      // parse the arguments
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANodeInternal Server: parse arguments\n")));
      int_server_result = parse_args (argc, argv);
      if (int_server_result != 0)
        return int_server_result;


       NEAInt_ServerTask neaint_servertask (intserver_thread_manager,
                 neaint_server_orb.in ());

      // Task activation flags. We create a lightweight process and wait to
      // have the thread send its status back.
      long flags =
        THR_NEW_LWP |
        THR_JOINABLE |
        neaint_server_orb->orb_core ()->orb_params ()->thread_creation_flags ();

       ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("NEANode: spawn a task\n")));
      int_server_result =
        neaint_servertask.activate (flags);
      if (int_server_result == -1)
        {
          // check what could have gone wrong. Maybe we did not have
          // permissions to run the real-time stuff.
          if (errno == EPERM)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 "Cannot create thread with scheduling policy %s\n"
                                 "because the user does not have the appropriate privileges, terminating program....\n"
                                 "Check svc.conf options and/or run as root\n",
                                 sched_policy_name (neaint_server_orb->orb_core ()->orb_params ()->ace_sched_policy ())),
                                2);
            }
          else
            // Unexpected error.
            ACE_ASSERT (0);
         }

      ACE_ASSERT (int_server_result != -1);
    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Exception caught");
      return -1;
    }

//************* End of NEANode_InternalServer Thread for Sensors

    client_result = thread_manager.wait();
    result = server_thread_manager.wait();
    int_client_result = intclient_thread_manager.wait();
    int_server_result = intserver_thread_manager.wait();
   return 0;

}
